/*************************************************************************
    > File Name: pmw-server.h
    > Author: wtao
    > Mail: tao.wang0221@gmail.com 
 ************************************************************************/

#ifndef _H_PMWS_INTERNAL_
#define _H_PMWS_INTERNAL_

#ifdef __cplusplus
extern "C" {
#endif

#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <assert.h>

/* parameters macros */
#define MAXLEN 10000
#define MAXFD 5020
#define MAXNEVENTS  225
#define OUTHLEN sizeof(OUTTER_H)
#define INHLEN sizeof(INNER_H)
/* ring buffer operation macros */

/* packet type */
#define S_REQUEST 0x60
#define M_REQUEST 0x61
#define S_RESPONSE 0x10
#define M_RESPONSE 0x11
#define CONNECT 0x40

/* fd state */
#define CONN_LISTENING 0x1
#define CONN_DATA 0x10
#define CONN_NFV 0x100
#define CONN_PIPE 0x1000

#define BIND_PORT 12345
#define DEFAULT_DC 500

int serv_fd;
int serv_epfd;
struct sockaddr_in serv_addr_in;
pthread_t thread_id;

#define NUM_NFV_THREADS 3

struct nfv_process_contex {
	pthread_t pid;
	int epfd; /* unique epoll fd for this pthread */
} nfv_process_ctx[NUM_NFV_THREADS];

struct in_process {
	uint8_t ip;
	uint16_t port;
	int fd;
	int lk_fd;
};

// Tao: for in_process queue
struct in_process conn_que[MAXFD];
int que_st, que_ed, que_len;
pthread_mutex_t que_lock;

int vis_fd[MAXFD];
pthread_mutex_t vis_fd_lock;

typedef struct {
	char *buf;
	pthread_spinlock_t lock; // we may not use it
	int ind_st, ind_ed;
	int capacity; // MAXLEN
	int length;
} RINGBUF;

struct linked_fd {
	int tfd;
	struct linked_fd *next;
};

struct nfv_fd {
	//uint32_t ack;
	uint8_t src_ip;
	uint16_t port;

	int nf_fd;
	int state;
	RINGBUF rbuf;
	RINGBUF sbuf;
	struct linked_fd *head;		// only for the CONN_NFV
	struct linked_fd *tail;		// tail
	struct linked_fd *scur;		// sbuf current write

	// track the EPOLL events
	int tr_state;

	int is_active;
	int epfd;					// related epfd
};

struct nfv_fd nf_link[MAXFD];	// for memcached fds, including main and worker thread

struct ep_fd {
	int efd;					// epfd  PS: Not used anymore
	pthread_mutex_t lock;       // epfd lock
	pthread_cond_t sig;         // epfd conditional signal
	struct linked_fd *head;		// epfd-associated fds
};

struct ep_fd ep_link[MAXFD];	// for tracking the epfd with fds

static int mc_main_fd;
static int pipe_pair[MAXFD];

typedef struct {
	uint8_t type;
	uint8_t src_ip;
	uint16_t port;
	uint16_t num_msg;
	uint16_t len_msg;
	//uint32_t ack;
} OUTTER_H;

typedef struct {
	uint8_t type;
	uint8_t src_ip;
	uint16_t port;
	uint16_t num_msg;
	uint16_t len_msg;
	//uint32_t ack;
} INNER_H;

// for hash: new hashmap
#define HASHMAP_ACTIVE 1

typedef struct {
  int data;  // tfd
  int flags;
  unsigned long key; // (ip << 16) + port
} hEntry;

struct s_hashmap{
  hEntry* table;
  pthread_mutex_t hashlock;
  long size, count;
};

typedef struct s_hashmap HashMap;
HashMap *ht;

// initialize pmw
void pmw_init();
void pmw_fini();

void nfv_thread();
void nfv_process_thread(void *arg);

int find_fake_fd();
void initial_data(int tfd, int type, uint8_t ip, uint16_t port, int fd);

int decompose_packet(int fd, char *data, uint32_t len);
void compose_packet(int fd);

// epoll-related funcs, defined in ./include/event2/pmw.h



// ring buf ops
inline int rbuf_getlength(RINGBUF *rbuf);
inline int rbuf_getsparelen(RINGBUF *rbuf);
inline void rbuf_write(RINGBUF *rbuf, const char *buf, int size);
inline void rbuf_write_nolock(RINGBUF *rbuf, const char *buf, int size);
inline void rbuf_read(RINGBUF *rbuf, char *buf, int size);
inline void rbuf_read_nolock(RINGBUF *rbuf, char *buf, int size);
inline void rbuf_release(RINGBUF *rbuf, int len);


// hash table ops
HashMap* hashmapCreate(int startsize);
void hashmapInsert(HashMap*, const int data, unsigned long key);
int hashmapRemove(HashMap*, unsigned long key);
int hashmapGet(HashMap*, unsigned long key);

// epfd ops
int pm_epoll_create(int size);
int epfd_delete(int epfd, int fd);

#ifdef __cplusplus
}
#endif

#endif
